package cz.acies.data;

import java.sql.Connection;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;

import cz.acies.uniql.dialect.Dialect;
import cz.acies.uniql.metadata.DBMetaData;

public class DBConnector
{
	private static DBConnector instance = null;
	
	private String driver;
	private String url;
	private Properties props = null;
	private String dialectClass;
	
	private DBMetaData dbmd;
	private DataSource dataSource;
	
	private GenericObjectPool connectionPool;
	
	private DBConnector() {
		super();
	}

	public static DBConnector instance() {
		if (instance == null) {
			instance = new DBConnector();
		}
		return instance;
	}

	public void initialize() {
		try {
			if (props == null) { props = new Properties(); }
			if (props.isEmpty()) {	
				props.put("user", "root");
				props.put("password", "");
				props.put("useUnicode", "true");
				props.put("characterEncoding", "UTF8");
				props.put("characterSetResults", "UTF8");
			}			
			Class.forName(driver).newInstance();
						
			connectionPool = new GenericObjectPool();
			connectionPool.setMaxActive(100);

			ConnectionFactory cf = new DriverManagerConnectionFactory(url, props);

			PoolableConnectionFactory pcf = new PoolableConnectionFactory(cf, connectionPool, null, null, false, true);
			dataSource = new PoolingDataSource(connectionPool);
			
			Connection conn = null;
			try {
				conn = instance.conn();
				Class<?> c = Class.forName(""+dialectClass);
				Dialect dialect = (Dialect) c.newInstance(); 
				dbmd = new DBMetaData(dialect).initialize(conn);
			} catch (Exception exc) {
				exc.printStackTrace();
			} finally {
				if (conn != null) try { conn.close(); } catch (Exception exc) {}
			}
		} catch (Exception exc) {
			exc.printStackTrace();
		}		
	}
	
	// -----  -----------------------------------------------------------------
	
	/**
	 * Navrací hodnotu connection.
	 *
	 * @return vrací connection
	 * @throws Exception the exception
	 */
	public Connection conn() throws Exception {
		Connection conn = null;
		try {
			conn = dataSource.getConnection();
		} catch (Exception e) {
			throw e;
		}
		return conn;
	}

	/**
	 * Navrací hodnotu connection.
	 *
	 * @return - vrací hodnotu connection
	 * @throws Exception the exception
	 */
	public Connection getConnection() throws Exception {
		return this.conn();
	}

	/**
	 * Navrací hodnotu DataSource.
	 *
	 * @return - vrací hodnotu data source
	 */
	public DataSource getDataSource() {
		return dataSource;
	}

	/**
	 * Zadá hodnotu DataSource.
	 *
	 * @param dataSource nová hodnota data source
	 */
	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	// -----  -----------------------------------------------------------------

	public DBMetaData dbmd() {
		return dbmd;
	}

	// -----  -----------------------------------------------------------------
	
	public String getDriver() {
		return driver;
	}

	public void setDriver(String driver) {
		this.driver = driver;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public Properties getProps() {
		return props;
	}

	public void setProps(Properties props) {
		this.props = props;
	}

	public String getDialectClass() {
		return dialectClass;
	}

	public void setDialectClass(String dialectClass) {
		this.dialectClass = dialectClass;
	}

}
